#ifndef __VALUE_CONVERTER_H__
#define __VALUE_CONVERTER_H__

typedef bool	Boolean;
typedef int		Int32;

enum OperationType {
	OperationType_None		= 0,
	OperationType_Add       = 1,
	OperationType_Subtract  = 2,
	OperationType_Percent   = 3,
};

Int32 Calculate(
	/* [in] */ OperationType operationType,
	/* [in] */ Int32 value,
	/* [in] */ Int32 operand)
{
	switch (operationType) {
		case OperationType_None:
			return value;

		case OperationType_Add:
			return (value + operand);

		case OperationType_Subtract:
			return (value - operand);

		case OperationType_Percent:
			return (Int32)(value * (operand > 0 ? operand : -operand) / 100.0f);
	}

	printf("Invalid operation type!");
	return 0;
}

Int32 CalculateBack(
	/* [in] */ OperationType operationType,
	/* [in] */ Int32 value,
	/* [in] */ Int32 operand)
{
	switch (operationType) {
		case OperationType_None:
			return value;

		case OperationType_Add:
			return (value - operand);

		case OperationType_Subtract:
			return (value + operand);

		case OperationType_Percent:
			return (Int32)(value * 100.0f / (operand > 0 ? operand : -operand));
	}

	printf("Invalid operation type!");
	return 0;
}

template <typename SourceType, typename TargetType>
class ValueConverter
{
public:
	ValueConverter()
	{
		m_operationType = OperationType_None;
		m_operand = 0;
	}

	void SetOperation(
		/* [in] */ OperationType operationType,
		/* [in] */ Int32 operand)
	{
		m_operationType = operationType;
		m_operand = operand;
	}

	TargetType Convert(
		/* [in] */ SourceType value)
	{
		return (TargetType)Calculate(m_operationType, (Int32)value, m_operand);
	}

	SourceType ConvertBack(
		/* [in] */ TargetType value)
	{
		return (SourceType)CalculateBack(m_operationType, (Int32)value, m_operand);
	}

private:
	OperationType m_operationType;
	Int32 m_operand;
};

template<>
class ValueConverter<Boolean, Int32>
{
public:
	ValueConverter()
	{
		m_operationType = OperationType_None;
		m_operand = 0;
		m_trueValue = 1;
		m_falseValue = 0;
	}

	void SetOperation(
		/* [in] */ OperationType operationType,
		/* [in] */ Int32 operand)
	{
		m_operationType = operationType;
		m_operand = operand;
	}

	void Initialize(
		/* [in] */ Int32 trueValue,
		/* [in] */ Int32 falseValue)
	{
		m_trueValue = trueValue;
		m_falseValue = falseValue;
	}

	Int32 Convert(
		/* [in] */ Boolean value)
	{
		if (m_operationType == OperationType_None) {
			return (value ? m_trueValue : m_falseValue);
		}

		return Calculate(m_operationType, value ? m_trueValue : m_falseValue, m_operand);
	}

	Boolean ConvertBack(
		/* [in] */ Int32 value)
	{
		if (m_operationType == OperationType_None) {
			return (value == m_trueValue ? true : false);
		}

		return (m_trueValue == CalculateBack(m_operationType, value ? m_trueValue : m_falseValue, m_operand));
	}

private:
	OperationType m_operationType;
	Int32 m_operand;

	Int32 m_trueValue;
	Int32 m_falseValue;
};

#endif // __VALUE_CONVERTER_H__